classdef ALMIntegrationService < handle
    % ALMIntegrationService - ALM集成服务（中间层协调器）
    % 
    % 功能：
    % - 协调ALMCloudService、PRExportImportService、CRExportImportService
    % - 提供统一的高层API供GUI调用
    % - 管理PR/CR的完整业务流程
    % - 处理权限验证和业务规则
    %
    % 设计原则：
    % - 遵循DO-178规则第4条：架构分离原则，独立于GUI实现
    % - 遵循DO-178规则第2条：明确错误处理，不使用fallback机制
    % - 遵循DO-178规则第6条：调试友好原则，不随意添加try-catch
    %
    % 使用示例：
    %   % 获取单例实例
    %   almService = ALMIntegrationService.getInstance();
    %   almService = ALMIntegrationService.getInstance('DebugMode', true);
    %   
    %   [success, result] = almService.submitPR(prData);
    %   [success, prList] = almService.refreshPRList();
    %
    % 作者：DO-178项目开发团队
    % 日期：2025-10-26
    % 版本：2.0
    
    properties (Access = private)
        cloudService        % ALMCloudService实例
        currentUser         % 当前用户名
        userRole            % 当前用户角色（'admin' 或 'user'）
        debugMode           % 调试模式标志
        
        % 缓存数据
        prListCache         % PR列表缓存
        crListCache         % CR列表缓存
        userListCache       % 用户列表缓存
        projectListCache    % 项目列表缓存
    end
    
    methods (Access = private)
        
        function obj = ALMIntegrationService(varargin)
            % 私有构造函数 - 初始化ALM集成服务（单例模式）
            % 可选参数：ALMIntegrationService('DebugMode', true/false)
            
            % 解析输入参数
            obj.debugMode = false;  % 默认关闭调试模式
            if nargin > 0
                for i = 1:2:nargin
                    if strcmpi(varargin{i}, 'DebugMode')
                        obj.debugMode = varargin{i+1};
                    end
                end
            end
            
            % 基于规则第2条：如果无法初始化服务，明确报告错误，不fallback
            try
                obj.cloudService = ALMCloudService('DebugMode', obj.debugMode);
                if obj.debugMode
                    fprintf('✅ ALMIntegrationService已初始化\n');
                end
            catch ME
                error('ALMIntegrationService:InitFailed', ...
                    '无法初始化ALM云服务：%s', ME.message);
            end
            
            % 初始化用户信息
            obj.currentUser = getenv('username');
            if isempty(obj.currentUser)
                obj.currentUser = 'unknown';
                fprintf('⚠️ 无法获取当前用户名，将使用默认值: unknown\n');
            end
            
            % 获取用户角色（基于规则第2条：如果失败则明确报告）
            [success, roleResult] = obj.cloudService.getUserRole(obj.currentUser);
            if success && isfield(roleResult, 'role')
                obj.userRole = roleResult.role;
                fprintf('✅ 当前用户角色: %s\n', obj.userRole);
            else
                obj.userRole = 'user'; % 默认为普通用户
                fprintf('⚠️ 无法获取用户角色，将使用默认角色: user\n');
            end
            
            % 初始化缓存
            obj.prListCache = {};
            obj.crListCache = {};
            obj.userListCache = {};
            obj.projectListCache = {};
        end
    end
    
    methods (Static, Access = public)
        function obj = getInstance(varargin)
            % 获取ALMIntegrationService的单例实例
            % 输入：
            %   'DebugMode' - 可选，调试模式（默认false）
            % 输出：
            %   obj - ALMIntegrationService单例实例
            
            persistent instance;
            
            if isempty(instance) || ~isvalid(instance)
                instance = ALMIntegrationService(varargin{:});
                fprintf('✅ 创建ALMIntegrationService单例实例\n');
            end
            
            obj = instance;
        end
    end
    
    methods (Access = public)
        
        %% ==================== PR管理 ====================
        
        function [success, result] = submitPR(obj, prData)
            % 提交PR到ALM服务器
            % 输入：prData - PR数据结构体，必须包含必填字段
            % 输出：success - 提交成功标志, result - 服务器响应结果
            %
            % 必填字段验证：
            % - project: 项目名称
            % - issueNumber: PR编号
            % - reporter: 报告人
            % - approver: 审批人
            % - severity: 严重性
            % - problemDescription: 问题描述
            
            % 基于规则第2条：数据验证失败时明确报告错误
            validationError = obj.validatePRData(prData);
            if ~isempty(validationError)
                success = false;
                result.error = validationError;
                return;
            end
            
            % 调用云服务提交
            [success, result] = obj.cloudService.submitPR(prData);
            
            % 如果提交成功，清空缓存以便下次刷新
            if success
                obj.prListCache = {};
                fprintf('✅ PR提交成功，已清空缓存\n');
            end
        end
        
        function [success, prList] = refreshPRList(obj)
            % 刷新PR列表从服务器
            % 输出：success - 查询成功标志, prList - PR列表（cell array）
            
            [success, prList] = obj.cloudService.queryPRList();
            
            if success && ~isempty(prList)
                obj.prListCache = prList;
                fprintf('✅ 成功获取 %d 条PR记录\n', length(prList));
            else
                % 基于规则第2条：不fallback到缓存，返回空列表
                prList = {};
            end
        end
        
        function [success, result] = approvePR(obj, prId, approvalStatus, approvalComment)
            % 审批PR
            % 输入：
            %   prId - PR数据库ID
            %   approvalStatus - 审批状态（'approved' 或 'rejected'）
            %   approvalComment - 审批意见
            
            % 基于规则第2条：权限验证失败时明确报告错误
            if ~obj.isAdmin()
                success = false;
                result.error = '只有管理员才能执行审批操作';
                fprintf('❌ 权限验证失败: %s\n', result.error);
                return;
            end
            
            % 调用云服务审批
            [success, result] = obj.cloudService.approvePR(prId, approvalStatus, approvalComment);
            
            % 如果审批成功，清空缓存
            if success
                obj.prListCache = {};
                fprintf('✅ PR审批成功，已清空缓存\n');
            end
        end
        
        function [success, prDetail] = getPRDetail(obj, prId)
            % 获取PR详细信息
            % 输入：prId - PR数据库ID
            % 输出：success - 查询成功标志, prDetail - PR详细信息结构体
            
            [success, prDetail] = obj.cloudService.getPRDetail(prId);
        end
        
        function [success, result] = exportPRToJSON(obj, prData, filePath)
            % 导出PR到JSON文件
            % 输入：
            %   prData - PR数据结构体
            %   filePath - 输出文件路径
            
            try
                success = PRExportImportService.exportToJSON(prData, filePath);
                result.message = sprintf('PR已导出到: %s', filePath);
            catch ME
                success = false;
                result.error = sprintf('导出JSON失败: %s', ME.message);
            end
        end
        
        function [success, result] = exportPRToMarkdown(obj, prData, filePath)
            % 导出PR到Markdown文件
            
            try
                success = PRExportImportService.exportToMarkdown(prData, filePath);
                result.message = sprintf('PR已导出到: %s', filePath);
            catch ME
                success = false;
                result.error = sprintf('导出Markdown失败: %s', ME.message);
            end
        end
        
        function [success, prData] = importPRFromJSON(obj, filePath)
            % 从JSON文件导入PR
            
            try
                prData = PRExportImportService.importFromJSON(filePath);
                success = true;
            catch ME
                success = false;
                prData = struct();
                fprintf('❌ 导入JSON失败: %s\n', ME.message);
            end
        end
        
        %% ==================== CR管理 ====================
        
        function [success, result] = submitCR(obj, crData)
            % 提交CR到ALM服务器
            % 输入：crData - CR数据结构体，必须包含必填字段
            % 输出：success - 提交成功标志, result - 服务器响应结果
            %
            % 必填字段验证：
            % - ticketNumber: CR编号
            % - reporter: 报告人
            % - approver: 审批人
            % - severity: 严重性
            % - changeDescription: 变更描述
            
            % 基于规则第2条：数据验证失败时明确报告错误
            validationError = obj.validateCRData(crData);
            if ~isempty(validationError)
                success = false;
                result.error = validationError;
                return;
            end
            
            % 调用云服务提交
            [success, result] = obj.cloudService.submitCR(crData);
            
            % 如果提交成功，清空缓存
            if success
                obj.crListCache = {};
                fprintf('✅ CR提交成功，已清空缓存\n');
            end
        end
        
        function [success, crList] = refreshCRList(obj)
            % 刷新CR列表从服务器
            % 输出：success - 查询成功标志, crList - CR列表（cell array）
            
            [success, crList] = obj.cloudService.queryCRList();
            
            if success && ~isempty(crList)
                obj.crListCache = crList;
                fprintf('✅ 成功获取 %d 条CR记录\n', length(crList));
            else
                % 基于规则第2条：不fallback到缓存，返回空列表
                crList = {};
            end
        end
        
        function [success, result] = approveCR(obj, crId, approvalStatus, approvalComment)
            % 审批CR
            % 输入：
            %   crId - CR数据库ID
            %   approvalStatus - 审批状态（'approved' 或 'rejected'）
            %   approvalComment - 审批意见
            
            % 基于规则第2条：权限验证失败时明确报告错误
            if ~obj.isAdmin()
                success = false;
                result.error = '只有管理员才能执行审批操作';
                fprintf('❌ 权限验证失败: %s\n', result.error);
                return;
            end
            
            % 调用云服务审批
            [success, result] = obj.cloudService.approveCR(crId, approvalStatus, approvalComment);
            
            % 如果审批成功，清空缓存
            if success
                obj.crListCache = {};
                fprintf('✅ CR审批成功，已清空缓存\n');
            end
        end
        
        function [success, crDetail] = getCRDetail(obj, crId)
            % 获取CR详细信息
            % 输入：crId - CR数据库ID
            % 输出：success - 查询成功标志, crDetail - CR详细信息结构体
            
            [success, crDetail] = obj.cloudService.getCRDetail(crId);
        end
        
        function [success, result] = exportCRToJSON(obj, crData, filePath)
            % 导出CR到JSON文件
            
            try
                success = CRExportImportService.exportToJSON(crData, filePath);
                result.message = sprintf('CR已导出到: %s', filePath);
            catch ME
                success = false;
                result.error = sprintf('导出JSON失败: %s', ME.message);
            end
        end
        
        function [success, result] = exportCRToMarkdown(obj, crData, filePath)
            % 导出CR到Markdown文件
            
            try
                success = CRExportImportService.exportToMarkdown(crData, filePath);
                result.message = sprintf('CR已导出到: %s', filePath);
            catch ME
                success = false;
                result.error = sprintf('导出Markdown失败: %s', ME.message);
            end
        end
        
        function [success, crData] = importCRFromJSON(obj, filePath)
            % 从JSON文件导入CR
            
            try
                crData = CRExportImportService.importFromJSON(filePath);
                success = true;
            catch ME
                success = false;
                crData = struct();
                fprintf('❌ 导入JSON失败: %s\n', ME.message);
            end
        end
        
        %% ==================== 项目和基线管理 ====================
        
        function [success, projects] = getProjects(obj)
            % 获取项目列表
            % 输出：success - 查询成功标志, projects - 项目列表（cell array）
            
            % 如果有缓存，直接返回
            if ~isempty(obj.projectListCache)
                success = true;
                projects = obj.projectListCache;
                return;
            end
            
            % 从服务器获取
            [success, projects] = obj.cloudService.getProjects();
            
            if success && ~isempty(projects)
                obj.projectListCache = projects;
                fprintf('✅ 成功获取 %d 个项目\n', length(projects));
            else
                projects = {};
            end
        end
        
        function [success, baselines, projectName] = getBaselines(obj, project)
            % 获取基线列表
            % 输入：project（可选）- 项目名称，用于筛选
            % 输出：
            %   success - 查询成功标志
            %   baselines - 基线列表（cell array）
            %   projectName - 当前筛选的项目名称
            
            if nargin < 2
                project = '';
            end
            
            [success, baselines, projectName] = obj.cloudService.getBaselines(project);
            
            if success && ~isempty(baselines)
                fprintf('✅ 成功获取 %d 个基线\n', length(baselines));
            else
                baselines = {};
            end
        end
        
        %% ==================== 用户管理 ====================
        
        function [success, users] = getUsers(obj)
            % 获取用户列表（无需管理员权限）
            % 输出：success - 查询成功标志, users - 用户信息结构体
            
            % 如果有缓存，直接返回
            if ~isempty(obj.userListCache)
                success = true;
                users = obj.userListCache;
                return;
            end
            
            % 从服务器获取
            [success, users] = obj.cloudService.getUsers();
            
            if success && ~isempty(users)
                obj.userListCache = users;
                if isfield(users, 'users')
                    fprintf('✅ 成功获取 %d 个用户\n', length(users.users));
                end
            else
                users = struct('users', {}, 'admins', {});
            end
        end
        
        function [success, approvers] = getApprovers(obj)
            % 获取审批人列表
            % 输出：success - 查询成功标志, approvers - 审批人列表（cell array）
            % 
            % 基于规则第2条：明确错误处理，不使用fallback机制
            
            [success, data] = obj.cloudService.getApprovers();
            
            if success && ~isempty(data)
                % ALMCloudService.getApprovers()返回的是结构体，需要提取approvers字段
                if isstruct(data) && isfield(data, 'approvers')
                    % 提取审批人用户名列表
                    approversList = data.approvers;
                    
                    if isempty(approversList)
                        approvers = {};
                        fprintf('⚠️ 审批人列表为空\n');
                        return;
                    end
                    
                    % 处理approversList可能是结构体数组或cell数组
                    approvers = cell(length(approversList), 1);
                    for i = 1:length(approversList)
                        if isstruct(approversList)
                            % 结构体数组，提取username字段
                            if isfield(approversList(i), 'username')
                                approvers{i} = approversList(i).username;
                            else
                                % 结构体但没有username字段，使用第一个字段
                                fields = fieldnames(approversList(i));
                                if ~isempty(fields)
                                    approvers{i} = approversList(i).(fields{1});
                                else
                                    approvers{i} = sprintf('user_%d', i);
                                end
                            end
                        elseif iscell(approversList)
                            % cell数组，直接使用
                            approvers{i} = approversList{i};
                        else
                            % 其他类型，转换为字符串
                            approvers{i} = char(approversList(i));
                        end
                    end
                    
                    fprintf('✅ 成功获取 %d 个审批人\n', length(approvers));
                else
                    % 数据格式不正确，返回空
                    approvers = {};
                    success = false;
                    fprintf('❌ 审批人数据格式不正确: 缺少approvers字段\n');
                end
            else
                approvers = {};
                fprintf('❌ 获取审批人失败\n');
            end
        end
        
        function isAdminFlag = isAdmin(obj)
            % 检查当前用户是否为管理员
            % 输出：isAdminFlag - 是否为管理员（true/false）
            
            isAdminFlag = strcmp(obj.userRole, 'admin');
        end
        
        function userName = getCurrentUser(obj)
            % 获取当前用户名
            userName = obj.currentUser;
        end
        
        function role = getCurrentUserRole(obj)
            % 获取当前用户角色
            role = obj.userRole;
        end
        
        function [success, userRole] = getUserRole(obj, userName)
            % 查询指定用户的角色信息
            % 输入：userName - 用户名（可选，默认为当前用户）
            % 输出：
            %   success - 查询成功标志
            %   userRole - 用户角色信息结构体，包含role字段
            %
            % 基于规则第4条：封装ALMCloudService的getUserRole方法
            
            % 如果未指定用户名，使用当前用户
            if nargin < 2
                userName = obj.currentUser;
            end
            
            % 调用底层cloudService查询用户角色
            [success, userRole] = obj.cloudService.getUserRole(userName);
            
            if success && isfield(userRole, 'role')
                fprintf('✅ 成功获取用户 %s 的角色: %s\n', userName, userRole.role);
            else
                fprintf('❌ 获取用户角色失败\n');
                userRole = struct('role', 'user'); % 默认返回普通用户角色
            end
        end
        
        %% ==================== 系统管理 ====================
        
        function [success, result] = testConnection(obj)
            % 测试与ALM服务器的连接
            % 输出：success - 连接成功标志, result - 结果信息
            
            [success, result] = obj.cloudService.testConnection();
        end
        
        function clearCache(obj)
            % 清空所有缓存
            obj.prListCache = {};
            obj.crListCache = {};
            obj.userListCache = {};
            obj.projectListCache = {};
            fprintf('✅ 已清空所有缓存\n');
        end
        
    end
    
    methods (Access = private)
        
        function errorMsg = validatePRData(obj, prData)
            % 验证PR数据完整性
            % 输出：errorMsg - 错误消息，如果为空则验证通过
            % 
            % 基于规则第2条：明确错误处理
            
            errorMsg = '';
            
            if ~isstruct(prData)
                errorMsg = 'PR数据必须是结构体';
                return;
            end
            
            % 必填字段检查（API v2.0规格：11个必填字段）
            requiredFields = {'project', 'issueNumber', 'reporter', 'source', 'initialSeverity', ...
                'problemDescription', 'problemMechanism', 'relatedRequirements', ...
                'impactAnalysis', 'assignee', 'approver'};
            
            for i = 1:length(requiredFields)
                field = requiredFields{i};
                if ~isfield(prData, field) || isempty(prData.(field))
                    errorMsg = sprintf('缺少必填字段: %s', field);
                    return;
                end
            end
            
            % 严重性验证（initialSeverity字段）
            % 支持中文值：严重/一般
            validSeveritiesCN = {'严重', '一般'};
            validSeveritiesEN = {'Critical', 'Major', 'Minor', 'Trivial'};
            
            severityValue = prData.initialSeverity;
            if ~any(strcmp(severityValue, validSeveritiesCN)) && ~any(strcmp(severityValue, validSeveritiesEN))
                errorMsg = sprintf('无效的严重性级别: %s（有效值: %s 或 %s）', ...
                    severityValue, strjoin(validSeveritiesCN, ', '), strjoin(validSeveritiesEN, ', '));
                return;
            end
        end
        
        function errorMsg = validateCRData(obj, crData)
            % 验证CR数据完整性
            % 输出：errorMsg - 错误消息，如果为空则验证通过
            % 
            % 基于规则第2条：明确错误处理
            
            errorMsg = '';
            
            if ~isstruct(crData)
                errorMsg = 'CR数据必须是结构体';
                return;
            end
            
            % 必填字段检查（API v2.0规格：4个必填字段）
            % CR表单不需要severity字段
            requiredFields = {'ticketNumber', 'reporter', 'approver', 'changeDescription'};
            
            for i = 1:length(requiredFields)
                field = requiredFields{i};
                if ~isfield(crData, field) || isempty(crData.(field))
                    errorMsg = sprintf('缺少必填字段: %s', field);
                    return;
                end
            end
            
            % CR表单没有严重性验证要求
            % 可选字段包括：project, assignee, reportDate, changeSource, baseline, analysis, related_pr_id
        end
        
    end
end

